/**
 * 项目名：五位一体化工安全信息平台
 * 日期：    2019-11-24 23:34:52
 * Copyright (c) 2015- joysuch-版权所有
 */

package com.joysuch.wwyt.bp.service.impl;

import cn.zlg.common.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.api.dataaccess.DataAccessService;
import com.joysuch.wwyt.bp.bean.BaseAttachmentDto;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityAttachmentDescEditBean;
import com.joysuch.wwyt.bp.bean.BpDeviceFacilityInspectRecordBean;
import com.joysuch.wwyt.bp.bean.MhBindPointBean;
import com.joysuch.wwyt.bp.bean.facility.*;
import com.joysuch.wwyt.bp.entity.*;
import com.joysuch.wwyt.bp.entity.dsl.QBpProductionFacility;
import com.joysuch.wwyt.bp.entity.inspect.BpInspectPlan;
import com.joysuch.wwyt.bp.entity.inspect.BpInspectRecord;
import com.joysuch.wwyt.bp.entity.inspect.BpInspectType;
import com.joysuch.wwyt.bp.enums.*;
import com.joysuch.wwyt.bp.repository.*;
import com.joysuch.wwyt.bp.service.*;
import com.joysuch.wwyt.common.entity.CommonIndexNotify;
import com.joysuch.wwyt.common.enums.CommonIndexNotifyTypes;
import com.joysuch.wwyt.common.service.CommonIndexNotifyService;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.SimpleDateFormatCache;
import com.joysuch.wwyt.core.entity.BaseTypeGroupItem;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.repository.BaseTypeGroupItemDao;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BaseAttachmentRepositoryService;
import com.joysuch.wwyt.core.service.BizCodeGeneratorFacade;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.dataperm.annotation.DisableDataPermission;
import com.joysuch.wwyt.mh.bean.MhMonitoringPointBean;
import com.joysuch.wwyt.mh.entity.MhMajorHazard;
import com.joysuch.wwyt.mh.entity.MhMonitoringPoint;
import com.joysuch.wwyt.mh.repository.MhMajorHazardDao;
import com.joysuch.wwyt.mh.repository.MhMonitoringPointDao;
import com.joysuch.wwyt.mh.service.MhMonitoringPointService;
import com.joysuch.wwyt.patrol.mapper.PatrolRecordMapper;
import com.joysuch.wwyt.risk.entity.RiskPointEvaluationScl;
import com.joysuch.wwyt.risk.repository.RiskDistrictDao;
import com.joysuch.wwyt.risk.repository.RiskPointEvaluationSclDao;
import com.joysuch.wwyt.util.PageableUtil;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Collections.EMPTY_LIST;

@Service
@Transactional(rollbackFor = Exception.class)
public class BpProductionFacilityServiceImpl implements BpProductionFacilityService {

    @Autowired
    private MhMonitoringPointDao mhMonitoringPointDao;
    @Autowired
    private BpMonitoringPointRelDao relDao;
    @Autowired
    private BpProductionFacilityDao dao;
    @Autowired
    private BizCodeGeneratorFacade bizCodeGeneratorFacade;
    @Autowired
    private BpDeviceFacilityCollectionService deviceFacilityCollectionService;
    @Autowired
    private BaseTypeGroupItemDao baseTypeGroupItemDao;
    @Autowired
    private BpManufacturingTechDao bpManufacturingTechDao;
    @Autowired
    private BpDeviceFacilityCollectionDao deviceFacilityCollectionDao;
    @Autowired
    private BpProductionFacilityTypeDao bpProductionFacilityTypeDao;
    @Autowired
    private BpProductionFacilityTypeService bpProductionFacilityTypeService;
    @Autowired
    private MhMajorHazardDao mhMajorHazardDao;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private RiskDistrictDao riskDistrictDao;
    @Autowired
    private BaseAttachmentRepositoryService baseAttachmentRepositoryService;
    @Autowired
    private BpInspectRecordDetailRepository bpInspectRecordDetailRepository;
    @Autowired
    private BpInspectPlanRepository bpInspectPlanRepository;
    @Autowired
    private DataAccessService dataAccessService;
    @Autowired
    private CommonIndexNotifyService notifyService;
    @Autowired
    private BpDeviceFacilityMaintainRecordService maintainRecordService;
    @Autowired
    private RiskPointEvaluationSclDao riskPointEvaluationSclDao;
    @Autowired
    private BpInspectRecordRepository recordRepository;
    @Autowired
    private BpInspectPlanRepository planRepository;
    @Autowired
    private BpInspectTypeRepository typeRepository;
    @Autowired
    private MhMonitoringPointService mhMonitoringPointService;
    @Autowired
    private BpDeviceFacilityAttachmentDescService bpDeviceFacilityAttachmentDescService;
    @Autowired
    private BpDeviceFacilityAttachmentDescDao bpDeviceFacilityAttachmentDescDao;
    @Autowired
    private PatrolRecordMapper patrolRecordMapper;
    @Autowired
    private BpDeviceFacilityRepairRecordDao bpDeviceFacilityRepairRecordDao;

    @Autowired
    private BpProductionFacilityVideoDao bpProductionFacilityVideoDao;


    @Override
    public BpProductionFacility add(BpProductionAddBean entity) {
        BpProductionFacility bpf = new BpProductionFacility();
        BeanUtils.copyProperties(entity, bpf);
        if (StringUtils.isNotEmpty(entity.getCode())) {
            bpf.setCode(entity.getCode());
        } else {
            bpf.setCode(bizCodeGeneratorFacade.shengChanZhuangZhi());
        }
        if (entity.getMajorHazardId() != null) {
            MhMajorHazard one = mhMajorHazardDao.getOne(entity.getMajorHazardId());
            bpf.setMajorHazardUnitCode(one.getCode());
            bpf.setMajorHazardUnit(one.getName());
        }
        bpf.setLifecycle(DeviceFacilityLifecycles.PUT_INFO_USE.getId());
        bpf.setRepairState(DeviceFacilityRepairStates.OK.getId());
        bpf.setMaintenanceAmount(Double.valueOf(0));
        bpf.setRepairAmount(Double.valueOf(0));
        //新增设备默认运行
        bpf.setState(ProductionFacilityStates.RUNNING.getId());
        BpProductionFacility save = dao.save(bpf);
        checkBpProductionFacility(save);
        updateTypeDeviceCount(entity.getType());
        saveFacilityMonitoringPoints(bpf, entity.getMhMonitoringPointBean());
        addOrUpdateDeviceFacilitCollection(entity, bpf);

        //设备过期的到期提醒
        Long typeId = entity.getType();
        Date validityDate = entity.getValidityDate();
        if (typeId != null && validityDate != null) {
            notify(entity.getName(), save.getId(), typeId, validityDate);
        }
        //绑定监测点
        if (CollectionUtils.isNotEmpty(entity.getMonitorPointIds())) {
            MhBindPointBean mhBindPointBean = new MhBindPointBean();
            mhBindPointBean.setId(save.getId());
            mhBindPointBean.setMonitorPointIds(entity.getMonitorPointIds());
            bindMonitorPoint(mhBindPointBean, 0, null);
        }
        entity.setId(save.getId());
        //绑定摄像头
        addVideo(entity);

        //关联证书
        if (CollectionUtils.isNotEmpty(entity.getBaseAttachmentDtoList())) {
            for (BaseAttachmentDto baseAttachmentDto : entity.getBaseAttachmentDtoList()) {
                BpDeviceFacilityAttachmentDescEditBean deviceFacilityAttachment = new BpDeviceFacilityAttachmentDescEditBean();
                deviceFacilityAttachment.setDeviceFacilityId(save.getId());
                deviceFacilityAttachment.setAttachment(baseAttachmentDto.getAttachment());
                deviceFacilityAttachment.setRemark(baseAttachmentDto.getRemark());
                bpDeviceFacilityAttachmentDescService.add(deviceFacilityAttachment);
            }
        }

        //调数据接入接口
        dataAccessService.safeDevice(Lists.newArrayList(save));
        return save;
    }

    //检查设备编码是否重复
    private void checkBpProductionFacility(BpProductionFacility save) {
        int count = dao.countByCode(save.getCode());
        if (count > 1) {
            throw new IllegalArgumentException("设备编号已存在");
        }
    }

    public void addVideo(BpProductionAddBean entity){
        List<BpProductionFacilityVideo> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(entity.getSystemVideoIds())) {
            for (Long systemVideoId : entity.getSystemVideoIds()) {
                BpProductionFacilityVideo old = bpProductionFacilityVideoDao.findByDeviceFacilityIdAndSystemVideoId(entity.getId(), systemVideoId);
                if (old != null) {
                    throw new IllegalArgumentException("该监控视频已经绑定");
                }
            }
            int old=0;
            List<Long> oldList = bpProductionFacilityVideoDao.findByDeviceFacilityId(entity.getId());
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(oldList)){
                old=oldList.size();
            }
            if ((old+entity.getSystemVideoIds().size())>10){
                throw new IllegalArgumentException("摄像头只能添加10个");
            }
            for (Long systemVideoId : entity.getSystemVideoIds()) {
                BpProductionFacilityVideo bpProductionFacilityVideo = new BpProductionFacilityVideo();
                bpProductionFacilityVideo.setSystemVideoId(systemVideoId);
                bpProductionFacilityVideo.setDeviceFacilityId(entity.getId());
                bpProductionFacilityVideo.setCreateBy(Context.getCurrentUserId());
                bpProductionFacilityVideo.setCreateTime(new Date());
                bpProductionFacilityVideo.setTenentId(Context.getCurrentTenantId());
                bpProductionFacilityVideo.setOrgCode(Context.getCurrentOrgCode());
                list.add(bpProductionFacilityVideo);
            }
            bpProductionFacilityVideoDao.saveAll(list);
        }
    }

    /**
     * 生产装置的到期通知
     */
    @Override
    public void notify(String deviceName, Long id, Long typeId, Date validityDate) {
        BpProductionFacilityType type = bpProductionFacilityTypeDao.getOne(typeId);
        if (type != null && type.getExpireRemindOrNot() != null && type.getExpireRemindOrNot() == 1) {
            String remindType = type.getRemindType();
//            Integer days = CertificateRemindTypes.getDays(remindType);
            Integer days = Integer.valueOf(type.getRemindType());
            LocalDateTime needNotifyTime = DateTimeUtil.date2LocalDateTime(validityDate).minusDays(days);
            String expireDate = SimpleDateFormatCache.getYmdCh().format(validityDate);
            Byte userDepartFlag = type.getUserDepartFlag();
            List<Long> needNotifyUserList = Lists.newArrayList();
            if (userDepartFlag == 0) {
                String remindUserIdJson = type.getRemindUserIdJson();
                needNotifyUserList.addAll(JSON.parseArray(remindUserIdJson, Long.class));
            } else {
                Long departId = type.getDepartId();
                List<Long> longs = baseUserDao.findIdByDepartId(departId);
                needNotifyUserList.addAll(longs);
            }
            List<CommonIndexNotify> notifyList = Lists.newArrayList();
            for (Long userId : needNotifyUserList) {
                CommonIndexNotify notify = new CommonIndexNotify();
                notify.setEduCertUserId(id);
                notify.setType(CommonIndexNotifyTypes.PRODUCTION_FACILITY.getType());
                //需要提醒的日期在当前日期之前，则立即去通知
                if (needNotifyTime.isBefore(LocalDateTime.now())) {
                    notify.setRemindDateTime(LocalDateTime.now());
                    notify.setRemindDate(LocalDate.now());
                    notify.setQueueOrNot(1);
                    notify.setRemindedOrNot(1);
                } else {
                    notify.setRemindDateTime(needNotifyTime);
                    notify.setRemindDate(needNotifyTime.toLocalDate());
                }
                notify.setUserId(userId);
                notify.setNotifyMessage(CommonIndexNotifyTypes.PRODUCTION_FACILITY.getType() + "到期提醒:'" + deviceName + "'" + "将于" + expireDate + "到期");
                notifyList.add(notify);
            }
            if (CollectionUtils.isNotEmpty(notifyList)) {
                notifyService.saveList(notifyList);
            }
        }
    }

    /**
     * 到期通知(检查、检测、保养通用)
     */
    @Override
    public void remindNotify(String deviceName, Long id, Long recordId, Long typeId, Date notifyDate, Date checkValidDate, String notifyType, String messageSource) {
        BpProductionFacilityType type = bpProductionFacilityTypeDao.getOne(typeId);
        if (type != null && type.getExpireRemindOrNot() != null && type.getExpireRemindOrNot() == 1) {
//            String remindType = type.getRemindType();
//            Integer days = CertificateRemindTypes.getDays(remindType);
//            Integer days = Integer.valueOf(type.getRemindType());
//            LocalDateTime needNotifyTime = DateTimeUtil.date2LocalDateTime(validityDate).minusDays(days);
            String expireDate = SimpleDateFormatCache.getYmdCh().format(checkValidDate);
            Byte userDepartFlag = type.getUserDepartFlag();
            List<Long> needNotifyUserList = Lists.newArrayList();
            if (userDepartFlag == 0) {
                String remindUserIdJson = type.getRemindUserIdJson();
                needNotifyUserList.addAll(JSON.parseArray(remindUserIdJson, Long.class));
            } else {
                Long departId = type.getDepartId();
                List<Long> longs = baseUserDao.findIdByDepartId(departId);
                needNotifyUserList.addAll(longs);
            }
            List<CommonIndexNotify> notifyList = Lists.newArrayList();
            String notifyMessage = notifyType + "到期提醒:'" + deviceName + "'" + "将于" + expireDate + "到期";
            if (StringUtils.isNotBlank(messageSource)) {
                notifyMessage = notifyType + "到期提醒" + "(" + messageSource + ")" + ":'" + deviceName + "'" + "将于" + expireDate + "到期";
            }
            for (Long userId : needNotifyUserList) {
                CommonIndexNotify notify = new CommonIndexNotify();
                notify.setEduCertUserId(id);
                notify.setType(notifyType);
                //提醒日期在当前日期之前则直接提醒
                if (notifyDate.before(new Date())) {
                    notify.setRemindDateTime(LocalDateTime.now());
                    notify.setRemindDate(LocalDate.now());
                    notify.setRemindedOrNot(1);
                    notify.setQueueOrNot(1);
                } else {
                    notify.setRemindDateTime(DateTimeUtil.date2LocalDateTime(notifyDate));
                    notify.setRemindDate(DateTimeUtil.date2LocalDate(notifyDate));
                }
                notify.setUserId(userId);
                notify.setRecordId(recordId);
                notify.setNotifyMessage(notifyMessage);
                notifyList.add(notify);
            }
            if (CollectionUtils.isNotEmpty(notifyList)) {
                notifyService.saveList(notifyList);
            }
        }
    }

    void updateTypeDeviceCount(Long typeId) {
        if (typeId != null) {
            bpProductionFacilityTypeDao.updateDeviceCount(typeId);
        }
    }

    /**
     * @param entity
     * @param bpf
     */
    protected void addOrUpdateDeviceFacilitCollection(BpProductionAddBean entity, BpProductionFacility bpf) {
        String subtype = null;
        if (entity.getType() != null) {
            try {
                BaseTypeGroupItem one = baseTypeGroupItemDao.getOne(entity.getType());
                subtype = one.getName();
            } catch (Exception e) {
            }
        }
        BpDeviceFacilityCollection facility = deviceFacilityCollectionService.addOrUpdateProductionFacility(bpf.getId(),
                bpf.getCode(), entity.getName(), subtype, (Long) null, entity.getMajorHazardId(), entity.getLocation(),
                entity.getKeyEquipment());
        // deviceFacilityCollectionService.bindDeviceAndMonitorPointss(facility, entity.getMhMonitoringPointBean());
    }

    private void saveFacilityMonitoringPoints(BpProductionFacility bpf, List<MhMonitoringPointBean> monitorIds) {
        if (monitorIds == null) {
            return;
        }
        for (MhMonitoringPointBean aLong : monitorIds) {
            BpMonitoringPointRel bpMonitoringPointRel = new BpMonitoringPointRel();
            bpMonitoringPointRel.setRefType("production_facility");
            bpMonitoringPointRel.setRefId(bpf.getId());
            bpMonitoringPointRel.setMonitoringPointId(aLong.getId());
            relDao.save(bpMonitoringPointRel);
        }
    }

    @Override
    @Transactional
    public BpProductionFacility update(BpProductionAddBean entity) throws IllegalArgumentException{
        BpProductionFacility bpf = dao.getOne(entity.getId());
        Date oldValidityDate = bpf.getValidityDate();
        BeanUtils.copyProperties(entity, bpf);
        if (StringUtils.isNotEmpty(entity.getCode())) {
            bpf.setCode(entity.getCode());
        } else {
            bpf.setCode(bizCodeGeneratorFacade.shengChanZhuangZhi());
        }
        Long newTypeId = entity.getType();
        Long oldTypeId = bpf.getType();
        if (entity.getMajorHazardId() != null) {
            MhMajorHazard one = mhMajorHazardDao.getOne(entity.getMajorHazardId());
            bpf.setMajorHazardUnit(one.getName());
            bpf.setMajorHazardUnitCode(one.getCode());
        }
        bpf.setMajorHazardUnitCode(entity.getBelongNum());
        //修改维修状态
        if (entity.getId() != null) {
            int count = bpDeviceFacilityRepairRecordDao.countByDeviceFacilityIdAndNowDate(entity.getId(), new Date());
            if (count > 0) {
                bpf.setRepairState(DeviceFacilityRepairStates.REPAIRING.getId());
            } else {
                bpf.setRepairState(DeviceFacilityRepairStates.OK.getId());
            }
        }
        BpProductionFacility save = dao.save(bpf);

        //先解绑之前绑定的监测点
        List<Long> bindPointIds = new ArrayList<>();
        List<BpMonitoringPointRel> bpMonitoringPointRels = relDao.findByRefTypeAndRefId("production_facility", entity.getId());
        if (CollectionUtils.isNotEmpty(bpMonitoringPointRels)) {
            for (BpMonitoringPointRel bpMonitoringPointRel : bpMonitoringPointRels) {
                unbindMonitorPoint(entity.getId(), bpMonitoringPointRel.getMonitoringPointId());
            }
        }
        if (!CollectionUtils.isEmpty(bindPointIds)) {
            bindPointIds = bpMonitoringPointRels.stream().map(BpMonitoringPointRel::getMonitoringPointId).distinct().collect(Collectors.toList());
        }
        //再绑定新监测点
        if (CollectionUtils.isNotEmpty(entity.getMonitorPointIds())) {
            MhBindPointBean mhBindPointBean = new MhBindPointBean();
            mhBindPointBean.setId(save.getId());
            mhBindPointBean.setMonitorPointIds(entity.getMonitorPointIds());
            bindMonitorPoint(mhBindPointBean, 1, bindPointIds);
        }
        List<BpDeviceFacilityAttachmentDesc> bpDeviceFacilityAttachmentDescList = bpDeviceFacilityAttachmentDescDao.findAllByDeviceFacilityId(entity.getId());
        if (CollectionUtils.isNotEmpty(bpDeviceFacilityAttachmentDescList)) {
            for (BpDeviceFacilityAttachmentDesc bpDeviceFacilityAttachmentDesc : bpDeviceFacilityAttachmentDescList) {
                try {
                    bpDeviceFacilityAttachmentDescService.delete(bpDeviceFacilityAttachmentDesc.getId());
                } catch (Exception e) {
                    throw new IllegalArgumentException("关联附件无法删除请检查");
                }
            }
        }
        //再关联新的证书
        if (CollectionUtils.isNotEmpty(entity.getBaseAttachmentDtoList())) {
            for (BaseAttachmentDto baseAttachmentDto : entity.getBaseAttachmentDtoList()) {
                BpDeviceFacilityAttachmentDescEditBean deviceFacilityAttachment = new BpDeviceFacilityAttachmentDescEditBean();
                deviceFacilityAttachment.setDeviceFacilityId(save.getId());
                deviceFacilityAttachment.setAttachment(baseAttachmentDto.getAttachment());
                deviceFacilityAttachment.setRemark(baseAttachmentDto.getRemark());
                bpDeviceFacilityAttachmentDescService.add(deviceFacilityAttachment);
            }
        }
        //删除之前的记录
        bpProductionFacilityVideoDao.deleteByDeviceFacilityId(entity.getId());
        addVideo(entity);

        checkBpProductionFacility(save);
        if (!Objects.equals(oldTypeId, newTypeId)) {
            updateTypeDeviceCount(oldTypeId);
            updateTypeDeviceCount(newTypeId);
        }

        // List<BpMonitoringPointRel> m = relDao.findByRefTypeAndRefId("production_facility", save.getId());
        // for (BpMonitoringPointRel bpMonitoringPointRel : m) {
        // relDao.delete(bpMonitoringPointRel);
        // }
        // saveFacilityMonitoringPoints(bpf, entity.getMhMonitoringPointBean());
        addOrUpdateDeviceFacilitCollection(entity, bpf);

        Long typeId = entity.getType();
        Date validityDate = entity.getValidityDate();
        Long id = save.getId();
        //到期日期改变执行下面的逻辑
        //跟新后通知逻辑：如果已经remind不做变动，否则移除通知缓存并删除此通知
        if (validityDate != null && !validityDate.equals(oldValidityDate)) {
            removeNotify(id);
            if (typeId != null) {
                notify(entity.getName(), id, typeId, validityDate);
            }
        } else if (validityDate == null) {
            removeNotify(id);
        }

        // TODO 判断三个周期是否更改,并更改提醒
        //changeOrRemoveNotify(bpf,entity);
        // TODO 待实现更新逻辑
        // addOrUpdateDeviceFacilitCollection
        //调数据接入接口
        dataAccessService.safeDevice(Lists.newArrayList(save));
        return save;
    }

    /**
     * 移除生产装置的通知
     */
    @Override
    public void removeNotify(Long id) {
        List<CommonIndexNotify> list = notifyService.getByModelAndId(CommonIndexNotifyTypes.PRODUCTION_FACILITY.getType(), id);
        for (CommonIndexNotify notify : list) {
            if (notify != null && notify.getRemindedOrNot() == 0) {
                notifyService.cancelAndRemove(notify);
                notifyService.delete(notify.getId());
            }
        }
    }

    /**
     * 移除提醒通知（检查、检测、保养通用）
     */
    @Override
    public void removeRemindNotify(Long id, String type) {
        List<CommonIndexNotify> list = notifyService.getByModelAndId(type, id);
        for (CommonIndexNotify notify : list) {
            if (notify != null && notify.getRemindedOrNot() == 0) {
                notifyService.cancelAndRemove(notify);
                notifyService.delete(notify.getId());
            }
        }
    }

    @Override
    public Page<BpProductionFacilityListBean> findByPage(Pageable page, BpProductionSearchBean bpProductionSearchBean) {
        Predicate predicate1 = prepareSearchCondition(bpProductionSearchBean);

        Page<BpProductionFacility> all = dao.findAll(predicate1, page);
        ArrayList<BpProductionFacilityListBean> list = new ArrayList<>();
        for (BpProductionFacility facility : all) {
            BpProductionFacilityListBean p = new BpProductionFacilityListBean();
            //有无保养记录
            BeanUtils.copyProperties(facility, p);
            p.setHasMainTanRecord(maintainRecordService.hasMaintainRecord(facility.getId()));
            if (facility.getDepartId() != null) {
                BpDepart one = bpDepartDao.getOne(facility.getDepartId());
                p.setDepartId(one.getId());
                p.setDepartName(one.getName());
            }

            if ("Y".equals(facility.getKeyEquipment()) || "y".equals(facility.getKeyEquipment())) {
                p.setKeyEquipmentName("是");
                p.setKeyEquipment("Y");
            } else if ("N".equals(facility.getKeyEquipment()) || "n".equals(facility.getKeyEquipment())) {
                p.setKeyEquipmentName("否");
                p.setKeyEquipment("N");
            } else {
                p.setKeyEquipmentName("");
                p.setKeyEquipment("");
            }
            p.setStateName(ProductionFacilityStates.findNameById(facility.getState()));
            p.setState(facility.getState());
            if (facility.getType() != null) {
                Optional<BpProductionFacilityType> oft = bpProductionFacilityTypeDao.findById(facility.getType());
                if (oft.isPresent()) {
                    p.setTypeName(oft.get().getName());
                }
            }
            if (facility.getCraftId() != null) {
                BpManufacturingTech one1 = bpManufacturingTechDao.getOne(facility.getCraftId());
                if (one1 != null) {
                    p.setCraftName(one1.getName());
                    p.setCraftId(one1.getId());
                }
            }
            ArrayList<MhMonitoringPointBean> objects = new ArrayList<>();
            List<BpMonitoringPointRel> m = relDao.findByRefTypeAndRefId("production_facility", facility.getId());
            for (BpMonitoringPointRel rel : m) {
                if (rel.getMonitoringPointId() != null) {
                    Optional<MhMonitoringPoint> optionalPoint = mhMonitoringPointDao.findById(rel.getMonitoringPointId());
                    if (optionalPoint.isPresent()) {
                        MhMonitoringPoint one = optionalPoint.get();
                        MhMonitoringPointBean mhMonitoringPointBean = new MhMonitoringPointBean();
                        mhMonitoringPointBean.setId(one.getId());
                        mhMonitoringPointBean.setName(one.getName());
//                    MhPointValueAndSwitchStateBean bean = mhMonitoringRealTimeService.getValueAndSwitchgStateBean(one);
//                    mhMonitoringPointBean.setRealtimeValue(bean.getRealtimeValue());
                        //mhMonitoringPointBean.setRealtimeValue(one.getRealtimeValue());
                        mhMonitoringPointBean.setPointCode(one.getPointCode());
                        mhMonitoringPointBean.setMinitoringTypeName(one.getMhMonitoringType().getName());
                        objects.add(mhMonitoringPointBean);
                    }
                }
            }
            if (objects.isEmpty()) {
                p.setMhMonitoringPointBean(EMPTY_LIST);
            }
            p.setMhMonitoringPointBean(objects);
            p.setRepairStateName(DeviceFacilityRepairStates.findNameById(facility.getRepairState()));
            if (facility.getScrapRegisterUserId() != null) {
                p.setScrapRegisterUserName(baseUserDao.getBaseUserNameById(facility.getScrapRegisterUserId()));
            }
            // 备注
            p.setRemark(facility.getScrapDescription());
            if (facility.getMajorHazardId() != null) {
                Optional<MhMajorHazard> omh = mhMajorHazardDao.findById(facility.getMajorHazardId());
                if (omh.isPresent()) {
                    p.setMajorHazardName(omh.get().getName());
                }
            }
            list.add(p);
        }
        return new PageImpl<>(list, page, all.getTotalElements());
    }

    @Override
    public List<BpProductionFacility> findAllHaveLocation() {
        return dao.findAllHaveLocation();
    }

    @Override
    public Long getNumForHaveLocation(Integer flag) {
        QBpProductionFacility q = QBpProductionFacility.bpProductionFacility;
        Predicate predicate1 = q.isNotNull();
        predicate1 = ExpressionUtils.and(predicate1, ExpressionUtils
                .or(q.lifecycle.eq(DeviceFacilityLifecycles.PUT_INFO_USE.getId()), q.lifecycle.isNull()));
        if (null != flag && 1 == flag) {
            predicate1 = ExpressionUtils.and(predicate1, q.location.isNotNull());
        }
        return dao.count(predicate1);
    }

    private Predicate prepareSearchCondition(BpProductionSearchBean condition) {
        QBpProductionFacility q = QBpProductionFacility.bpProductionFacility;
        Predicate predicate1 = q.isNotNull();
        if (null != condition.getStatus() && 0 == condition.getStatus()) {
            predicate1 = ExpressionUtils.and(predicate1, q.location.isNull());
        } else if (null != condition.getStatus() && 1 == condition.getStatus()) {
            predicate1 = ExpressionUtils.and(predicate1, q.location.isNotNull());
        }
        predicate1 = condition.getName() == null ? predicate1
                : ExpressionUtils.and(predicate1,
                ExpressionUtils.or(q.name.like("%" + condition.getName() + "%"),
                        q.code.like("%" + condition.getName() + "%")));
        predicate1 = condition.getCode() == null ? predicate1
                : ExpressionUtils.and(predicate1, q.code.like(condition.getCode()));
        predicate1 = condition.getState() == null ? predicate1
                : ExpressionUtils.and(predicate1, q.state.eq(condition.getState()));
        if (condition.getRepairState() != null) {
            predicate1 = ExpressionUtils.and(predicate1, q.repairState.eq(condition.getRepairState()));
        }
        if (condition.getDepartId() != null) {
            predicate1 = ExpressionUtils.and(predicate1, q.departId.eq(condition.getDepartId()));
        }
        if (condition.getTypeId() != null && condition.getTypeId() != 0) {
            List<Long> typeIds = bpProductionFacilityTypeService.findChildrenIdList(condition.getTypeId());
            typeIds.add(condition.getTypeId());
            predicate1 = ExpressionUtils.and(predicate1, q.type.in(typeIds));
        }
        if (condition.getSafeStatus() != null) {
            predicate1 = ExpressionUtils.and(predicate1, q.safeStatus.eq(condition.getSafeStatus()));
        }
        if (condition.getMajorHazardId() != null) {
            predicate1 = ExpressionUtils.and(predicate1, q.majorHazardId.eq(condition.getMajorHazardId()));
        }
        // 默认查询投用状态列表
        if (DeviceFacilityLifecycles.SCRAPED.is(condition.getType())) {
            // 报废
            predicate1 = ExpressionUtils.and(predicate1, q.lifecycle.eq(DeviceFacilityLifecycles.SCRAPED.getId()));
        } else {
            predicate1 = ExpressionUtils.and(predicate1, ExpressionUtils
                    .or(q.lifecycle.eq(DeviceFacilityLifecycles.PUT_INFO_USE.getId()), q.lifecycle.isNull()));
        }
        if (StringUtils.isNotBlank(condition.getMajorHazardCode())) {
            predicate1 = ExpressionUtils.and(predicate1, q.majorHazardUnitCode.eq(condition.getMajorHazardCode()));
        }
        return predicate1;
    }

    /**
     * 批量删除
     *
     * @param ids 设备id集合
     */
    @Override
    public void deleteByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new IllegalArgumentException("请选择需要删除的设备");
        }
        for (Long id : ids) {
            this.delete(id);
        }
    }

    @Override
    public void delete(Long id) {
        BpProductionFacility one = dao.getOne(id);
        //删除设置
        // checkProductFacility(id);
        if (one.getType() != null) {
            BpProductionFacilityType type = bpProductionFacilityTypeDao.findById(one.getType()).orElse(null);
            if (type != null) {
                type.setNumber((int) dao.count(QBpProductionFacility.bpProductionFacility.type.eq(one.getType())));
            }
        }
        //解除设备与监测点的关联关系
        relDao.deleteByRefTypeAndRefId("production_facility", id);
        dao.deleteById(id);
        //删除移除通知
        removeNotify(id);
        deviceFacilityCollectionService.delteByDeviceTypeAndDeviceId(DeviceFacilityTypes.SHENG_CHAN_ZHUANG_ZHI, id);
    }

    //设备删除判断
    private void checkProductFacility(Long productFacilityId) {
        List<RiskPointEvaluationScl> fList = riskPointEvaluationSclDao.findByFacilityId(productFacilityId);
        if (fList.size() > 0) {
            throw new IllegalArgumentException("请先删除设备和控制风险评估SCL评估的绑定关系");
        }
    }

    @Override
    @DisableDataPermission(recursive = true)
    public BpProductionFacilityListBean findById(Long id) {
        BpProductionFacility facility = dao.findById(id).get();
        BpProductionFacilityListBean p = new BpProductionFacilityListBean();
        if (facility.getDepartId() != null) {
            BpDepart one = bpDepartDao.getOne(facility.getDepartId());
            p.setDepartId(one.getId());
            p.setDepartName(one.getName());
        }
        p.setHasMainTanRecord(maintainRecordService.hasMaintainRecord(facility.getId()));
        p.setValidityDate(facility.getValidityDate());
        p.setId(facility.getId());
        p.setCode(facility.getCode());
        p.setEquipmentModel(facility.getEquipmentModel());
        p.setFunctions(facility.getFunctions());
        if ("Y".equals(facility.getKeyEquipment()) || "y".equals(facility.getKeyEquipment())) {
            p.setKeyEquipmentName("是");
            p.setKeyEquipment("Y");
        } else if ("N".equals(facility.getKeyEquipment()) || "n".equals(facility.getKeyEquipment())) {
            p.setKeyEquipmentName("否");
            p.setKeyEquipment("N");
        } else {
            p.setKeyEquipmentName("");
            p.setKeyEquipment("");
        }
        if (facility.getMajorHazardId() != null) {
            MhMajorHazard mh = mhMajorHazardDao.findById(facility.getMajorHazardId()).orElse(null);
            if (mh != null) {
                p.setMajorHazardUnitCode(mh.getCode());
                p.setMajorHazardUnit(mh.getName());
            }
        }

        p.setLocation(facility.getLocation());
        p.setMajorHazardId(facility.getMajorHazardId());

        p.setName(facility.getName());
        p.setProductionAbility(facility.getProductionAbility());
        if (facility.getState() == null) {
            p.setStateName("");
        } else if (facility.getState() == 0) {
            p.setStateName("运行");
            p.setState(0);
        } else if (facility.getState() == 1) {
            p.setStateName("停产");
            p.setState(1);
        } else if (facility.getState() == 2) {
            p.setStateName("检修");
            p.setState(2);
        }
        if (facility.getType() != null) {
            BpProductionFacilityType one2 = bpProductionFacilityTypeDao.getOne(facility.getType());
            p.setTypeName(one2.getName());
        }
        p.setTechnicalCondition(facility.getTechnicalCondition());
        p.setTenentId(facility.getTenentId());
        p.setType(facility.getType());
        if (facility.getCraftId() != null) {
            BpManufacturingTech one1 = bpManufacturingTechDao.getOne(facility.getCraftId());
            if (one1 != null) {
                p.setCraftName(one1.getName());
                p.setCraftId(one1.getId());
            }
        }
        ArrayList<MhMonitoringPointBean> objects = new ArrayList<>();
        List<BpMonitoringPointRel> m = relDao.findByRefTypeAndRefId("production_facility", id);
        for (BpMonitoringPointRel rel : m) {
            MhMonitoringPoint one = mhMonitoringPointDao.getOne(rel.getMonitoringPointId());
            MhMonitoringPointBean mhMonitoringPointBean = new MhMonitoringPointBean();
            mhMonitoringPointBean.setId(one.getId());
            mhMonitoringPointBean.setName(one.getName());
            mhMonitoringPointBean.setRealtimeValue(one.getRealtimeValue());
            mhMonitoringPointBean.setPointCode(one.getPointCode());
            mhMonitoringPointBean.setMinitoringTypeName(one.getMhMonitoringType().getName());
            objects.add(mhMonitoringPointBean);
        }
        if (objects.isEmpty()) {
            p.setMhMonitoringPointBean(EMPTY_LIST);
        }
        p.setMhMonitoringPointBean(objects);

        p.setDeviceLocation(facility.getDeviceLocation());
        p.setRiskDistrictId(facility.getRiskDistrictId());
        p.setRiskDistrictName(riskDistrictDao.findNameById(facility.getRiskDistrictId()));
        p.setPersonInChargeId(facility.getPersonInChargeId());
        p.setPersonInChargeName(baseUserDao.getBaseUserNameById(facility.getPersonInChargeId()));
        p.setPicDepartId(facility.getPicDepartId());
        p.setPicDepartName(bpDepartDao.findDepartNameById(facility.getPicDepartId()));
        p.setManufactureDate(facility.getManufactureDate());
        p.setPutIntoUseDate(facility.getPutIntoUseDate());
        p.setServiceLifeMonths(facility.getServiceLifeMonths());
        p.setMaintainPeriodDays(facility.getMaintainPeriodDays());
        p.setRemindAheadDays(facility.getRemindAheadDays());
        p.setRepairState(facility.getRepairState());
        p.setRepairStateName(DeviceFacilityRepairStates.findNameById(facility.getRepairState()));
        p.setLifecycle(facility.getLifecycle());
        p.setLifecycleName(DeviceFacilityLifecycles.findNameById(facility.getLifecycle()));
        p.setSafeStatus(facility.getSafeStatus());
        p.setMaintenanceAmount(facility.getMaintenanceAmount());
        p.setRepairAmount(facility.getMaintenanceAmount());

        p.setTagNumber(facility.getTagNumber());
        p.setSupplier(facility.getSupplier());
        p.setInspectionDays(facility.getInspectionDays());
        p.setDetectDays(facility.getDetectDays());
        return p;
    }

    @Override
    public void save(BpProductionFacility bpProductionFacility) {
        dao.save(bpProductionFacility);
    }

    @Override
    public void scrapFacility(BpProductionFacilityScrapBean bean) {
        BpProductionFacility one = dao.getOne(bean.getId());
        BeanUtils.copyProperties(bean, one, "id");
        if (bean.getScrapAttachment() != null) {
            one.setScrapAttachmentId(bean.getScrapAttachment().getId());
        } else {
            one.setScrapAttachmentId(null);
        }
        one.setLifecycle(DeviceFacilityLifecycles.SCRAPED.getId());
        dao.save(one);
    }

    @Override
    public BpProductionFacilityScrapBean getScrapInfo(Long id) {
        BpProductionFacility one = dao.getOne(id);
        BpProductionFacilityScrapBean bean = new BpProductionFacilityScrapBean();
        if (one.getScrapAttachmentId() != null) {
            bean.setScrapAttachment(baseAttachmentRepositoryService.findByIdIntoBean(one.getScrapAttachmentId()));
        }
        bean.setId(one.getId());
        bean.setScrapDescription(one.getScrapDescription());
        bean.setScrapRegisterTime(one.getScrapRegisterTime());
        bean.setScrapRegisterUserId(one.getScrapRegisterUserId());
        if (one.getScrapRegisterUserId() != null) {
            bean.setScrapRegisterUserName(baseUserDao.getBaseUserNameById(one.getScrapRegisterUserId()));
        }
        bean.setScrapDate(one.getScrapDate());
        return bean;
    }

    @Override
    public String bindMonitorPoint(MhBindPointBean bean, Integer flag, List<Long> bindPointIds) {
        String errorMessage = null;
        // 检查监测点中是否存在已被关联的点
        if (!org.springframework.util.CollectionUtils.isEmpty(bean.getMonitorPointIds())) {
            for (Long monitorPointId : bean.getMonitorPointIds()) {
                errorMessage = mhMonitoringPointService.checkMhMointPoint(monitorPointId, bean.getId());
                if (StringUtils.isNotBlank(errorMessage)) {
                    return errorMessage;
                }
            }
        }
        //只有存在且运行的设备才能绑定监测点
        BpProductionFacility pf = dao.findById(bean.getId()).orElseThrow(() -> new IllegalArgumentException("设备不存在"));
        if (pf.getState() != null && pf.getState().intValue() == ProductionFacilityStates.STOPED.getId() && flag.equals(0)) {
            if (flag != null && flag.equals(1)) {
                //修改 如有新的监测点要绑定才提示
                if (!CollectionUtils.isEmpty(bean.getMonitorPointIds())) {
                    for (Long id : bean.getMonitorPointIds()) {
                        if (!bindPointIds.contains(id)) {
                            throw new IllegalArgumentException("请恢复该设备再绑定监测点");
                        }
                    }
                }

            } else {
                //新增 绑定 直接根据设备状态来判断
                throw new IllegalArgumentException("请恢复该设备再绑定监测点");
            }
        }
        // 做绑定动作
        if (!org.springframework.util.CollectionUtils.isEmpty(bean.getMonitorPointIds())) {
            for (Long monitorPointId : bean.getMonitorPointIds()) {
                List<BpMonitoringPointRel> list = relDao.findByRefTypeAndRefIdAndMonitoringPointId("production_facility", bean.getId(),
                        monitorPointId);
                if (list.size() == 0) {
                    BpMonitoringPointRel bpMonitoringPointRel = new BpMonitoringPointRel();
                    bpMonitoringPointRel.setRefType("production_facility");
                    bpMonitoringPointRel.setRefId(bean.getId());
                    bpMonitoringPointRel.setMonitoringPointId(monitorPointId);
                    relDao.save(bpMonitoringPointRel);
                    deviceFacilityCollectionService.bindMonitorPoint(DeviceFacilityTypes.SHENG_CHAN_ZHUANG_ZHI, bean.getId(),
                            monitorPointId);
                }
            }
        }
        return null;
    }

    @Override
    public void unbindMonitorPoint(Long id, Long monitorPointId) {
        relDao.deleteByRefTypeAndRefIdAndMonitoringPointId("production_facility", id,
                monitorPointId);
        deviceFacilityCollectionService.unbindMonitorPoint(DeviceFacilityTypes.SHENG_CHAN_ZHUANG_ZHI, id,
                monitorPointId);
    }

    @Override
    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<BpDeviceFacilityInspectRecordBean> findInspectRecordPage(Pageable page, Long deviceFacilityId) {
        // System.err.println(bpInspectRecordDetailRepository);
        // 获取设备在collection表中的id
        BpDeviceFacilityCollection facilityCollection = deviceFacilityCollectionDao.findFirstByDeviceTypeNameAndDeviceId(DeviceFacilityTypes.SHENG_CHAN_ZHUANG_ZHI.getName(), deviceFacilityId);
        if (facilityCollection != null) {
            deviceFacilityId = facilityCollection.getId();
        }
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<BpDeviceFacilityInspectRecordBean> iPage = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page.getPageNumber() + 1, page.getPageSize());
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<BpDeviceFacilityInspectRecordBean> result = patrolRecordMapper.getRecordByDeviceId(iPage, deviceFacilityId);
        return result;
    }

    @Override
    public BpProductionFacility findByCode(String code, String companyCode) {
        return dao.findByCodeAndCompanyCode(code, companyCode);
    }

    @Override
    public BpProductionFacility findByCodeAndCompanyCode(String code, String companyCode) {
        return dao.findByCodeAndCompanyCode(code, companyCode);
    }

    @Override
    public BpProductionFacility findOne(Long deviceId) {
        Optional<BpProductionFacility> optional = dao.findById(deviceId);
        return optional.orElse(null);
    }

    private String findInspectTypeNameByPlanId(Long inspectPlanId) {
        return bpInspectPlanRepository.findInspectTypeNameById(inspectPlanId);
    }

    /**
     * 判断是否更改三个周期,更改后需要更改未提醒的通知
     *
     * @param entity
     * @param bean
     */
    private void changeOrRemoveNotify(BpProductionFacility entity, BpProductionAddBean bean) {
        //原保养周期
        Integer oldMaintainPeriodDays = entity.getMaintainPeriodDays();
        //现保养周期
        Integer newMaintainPeriodDays = bean.getMaintainPeriodDays();
        //原检测周期
        Integer oldDetectDays = entity.getDetectDays();
        //现检测周期
        Integer newEtectDays = bean.getDetectDays();
        //原检查周期
        Integer oldInspectionDays = entity.getInspectionDays();
        //现检查周期
        Integer newInspectionDays = bean.getInspectionDays();
        compare(entity.getType(), entity.getId(), oldMaintainPeriodDays, newMaintainPeriodDays, CommonIndexNotifyTypes.PRODUCTION_FACILITY_MAINTAINANCE);
        compare(entity.getType(), entity.getId(), oldDetectDays, newEtectDays, CommonIndexNotifyTypes.PRODUCTION_FACILITY_DETECT);
        compare(entity.getType(), entity.getId(), oldInspectionDays, newInspectionDays, CommonIndexNotifyTypes.PRODUCTION_FACILITY_CHECK);
    }

    private void compare(Long typeId, Long id, Integer original, Integer now, CommonIndexNotifyTypes types) {
        if (now != null && !original.equals(now)) {
            //remove and change notify  移除还未提醒的通知,并按照现在的规则重新生成

        } else if (now == null) {

            //remove notify
        }
    }

    /**
     * 移除所有未通知的提醒
     *
     * @param typeId
     * @param id
     * @param now
     * @param types
     */
    private void removeNotify(Long typeId, Long id, Integer now, CommonIndexNotifyTypes types) {
        switch (types) {
            case PRODUCTION_FACILITY_MAINTAINANCE:
                removeMaintainancENotify(id, types);
                break;

            case PRODUCTION_FACILITY_CHECK:

            case PRODUCTION_FACILITY_DETECT:
        }
    }

    /**
     * 移除设备装置id对应的未提醒信息
     *
     * @param id
     */
    private void removeMaintainancENotify(Long id, CommonIndexNotifyTypes types) {
        List<CommonIndexNotify> list = notifyService.getByModelAndId(types.getType(), id);
        for (CommonIndexNotify notify : list) {
            if (notify != null && notify.getRemindedOrNot() == 0) {
                notifyService.delete(notify.getId());
            }
        }
    }

}
